package com.jeesite.modules.fl.service;


import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.validation.ConstraintViolationException;

import com.jeesite.common.utils.SmsUtils;
import com.jeesite.modules.config.web.WeixinProperties;
import com.jeesite.modules.fl.dao.EvaluateDao;
import com.jeesite.modules.fl.dao.EvaluateDetailDao;
import com.jeesite.modules.fl.entity.*;

import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.jeesite.common.entity.Page;
import com.jeesite.common.lang.DateUtils;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.service.CrudService;
import com.jeesite.common.service.ServiceException;
import com.jeesite.common.utils.excel.ExcelImport;
import com.jeesite.common.validator.ValidatorUtils;
import com.jeesite.modules.fl.dao.AppointmentDao;
import com.jeesite.modules.sys.entity.User;
import com.jeesite.modules.sys.service.UserService;
import com.jeesite.modules.sys.utils.DictUtils;


@Service
@Transactional(readOnly=true)
public class AppointmentService extends CrudService<AppointmentDao,Appointment>{
	private static final Logger logger = LoggerFactory.getLogger(AppointmentService.class);
	private static final String WX_TEXT_COLOR = "#063c68";
	@Autowired
	private ActionRecordService recordService;
	@Autowired
	private DoctorService doctorService;
	@Autowired
	private ClinicService clinicService;
	@Autowired
	private EvaluateDao evaluateDao;
	@Autowired
	private EvaluateDetailDao evaluateDetailDao;
	@Autowired
	private ClinicSettingService clinicSettingService;
	@Autowired
	private LeaguerService leaguerService;
	@Autowired
	private UserService userService;
	@Autowired
	private WeixinProperties weixinProperties;
	@Autowired
	private WxMpService wxMpService;
	
	/**
	 * 获取单条数据
	 * @param appointment
	 * @return
	 */
	@Override
	public Appointment get(Appointment appointment) {
		Appointment entity = super.get(appointment);
		if(!entity.getIsNewRecord()){
			ActionRecord recored = new ActionRecord();
			recored.setStatus("0");
			recored.setAppointment(entity);
			entity.setRecords(recordService.findList(recored));

			getEvaluates(getEvaluate(entity));
		}
		return entity;
	}

	//获取所有评价内容
	public Appointment getEvaluate(Appointment entity){
		//获取评价
		Evaluate evaluate = new Evaluate(entity);
		evaluate.setStatus(Evaluate.STATUS_NORMAL);
		entity.setEvaluateList(evaluateDao.findList(evaluate));

		//获取评价明细
		EvaluateDetail evaluateDetail = new EvaluateDetail(entity);
		evaluateDetail.setStatus(EvaluateDetail.STATUS_NORMAL);
		entity.setEvaluateDetailList(evaluateDetailDao.findList(evaluateDetail));
		return entity;
	}

	/**
	 * 更新评价内容的读取状态
	 * @param appointment
	 */
	@Transactional(readOnly=false)
	public void updateEvaluateDetailRead(Appointment appointment){
		EvaluateDetail filter = new EvaluateDetail(appointment);
		filter.setStatus(EvaluateDetail.STATUS_NORMAL);
		filter.setReadFlag("0");
		List<EvaluateDetail> evalDeatilList =  evaluateDetailDao.findList(filter);
		for(EvaluateDetail evaluateDetail: evalDeatilList){
			evaluateDetail.setReadFlag("1");
			evaluateDetail.preUpdate();
			evaluateDetailDao.update(evaluateDetail);
		}
	}
	
	public Appointment getByNo(String no) {
		return dao.getByNo(no);
	}

	public List<Appointment> getEvaluates(Appointment appointment){return dao.getEvaluates(appointment);}
	
	/**
	 * 查询分页数据
	 * @param page 分页对象
	 * @param appointment
	 * @return
	 */
	@Override
	public Page<Appointment> findPage(Page<Appointment> page, Appointment appointment) {
		return super.findPage(page, appointment);
	}
	
	public Integer getCountByNoPref(String noPref) {
        return dao.getCountByNoPref(noPref);
    }

    //设置预约号
    public void setAppointmentNo(Appointment appointment){
        if(StringUtils.isBlank(appointment.getId())) {
            SimpleDateFormat dateFormater = new SimpleDateFormat("yyyyMMdd");
            Clinic clinic = null;
            if(appointment.getClinic() != null && appointment.getClinic().getId() != null){
            	clinic = clinicService.get(appointment.getClinic().getId());
            }else{
            	clinic = new Clinic();
            }
            String noPref = String.format("%s%s%s", getProvinceShortName(clinic.getProvince().getAreaName()),clinic.getShortName(), dateFormater.format(new Date()));
            Integer count;
            count = getCountByNoPref(noPref);
            DecimalFormat df=new DecimalFormat("0000");
            String str2=df.format(count+1);
            appointment.setNo(String.format("%s%s",noPref,str2));
        }
    }
    
    private String getProvinceShortName(String province){
    	if("北京市".equals(province)){
    		return "BJ";
    	}else if("上海市".equals(province)){
    		return "SH";
    	}else if("天津市".equals(province)){
    		return "TJ";
    	}else if("河北省".equals(province)){
    		return "HB";
    	}else if("山西省".equals(province)){
    		return "SX";
    	}else if("内蒙古自治区".equals(province)){
    		return "NM";
    	}else if("辽宁省".equals(province)){
    		return "LN";
    	}else if("吉林省".equals(province)){
    		return "JL";
    	}else if("黑龙江省".equals(province)){
    		return "HL";
    	}else if("江苏省".equals(province)){
    		return "JS";
    	}else if("浙江省".equals(province)){
    		return "ZJ";
    	}else if("安徽省".equals(province)){
    		return "AH";
    	}else if("福建省".equals(province)){
    		return "FJ";
    	}else if("江西省".equals(province)){
    		return "SX";
    	}else if("山东省".equals(province)){
    		return "SD";
    	}else if("河南省".equals(province)){
    		return "HN";
    	}else if("湖北省".equals(province)){
    		return "HB";
    	}else if("湖南省".equals(province)){
    		return "HN";
    	}else if("广东省".equals(province)){
    		return "GD";
    	}else if("广西壮族自治区".equals(province)){
    		return "GX";
    	}else if("海南省".equals(province)){
    		return "HN";
    	}else if("重庆市".equals(province)){
    		return "CQ";
    	}else if("四川省".equals(province)){
    		return "SC";
    	}else if("黑龙江省".equals(province)){
    		return "HL";
    	}else if("贵州省".equals(province)){
    		return "GZ";
    	}else if("云南省".equals(province)){
    		return "YN";
    	}else if("西藏自治区".equals(province)){
    		return "XZ";
    	}else if("陕西省".equals(province)){
    		return "SX";
    	}else if("甘肃省".equals(province)){
    		return "GS";
    	}else if("青海省".equals(province)){
    		return "QH";
    	}else if("宁夏回族自治区".equals(province)){
    		return "NX";
    	}else if("新疆维吾尔自治区".equals(province)){
    		return "XJ";
    	}else if("台湾省".equals(province)){
    		return "TW";
    	}else if("香港特别行政区".equals(province)){
    		return "XG";
    	}else if("澳门特别行政区".equals(province)){
    		return "AM";
    	}
    	return "";
    }
    
    public int getAppointmentLimitDay(Clinic clinic, String department){
    	ClinicSetting entity = new ClinicSetting();
    	entity.setClinic(clinic);
    	entity.setDepartment(department);
    	entity.setStatus("0");
    	List<ClinicSetting> settingList = clinicSettingService.findList(entity);
    	if(settingList.size()>0){
    		ClinicSetting setting = settingList.get(0);
    		return new Double(new Double(setting.getAmEndTime()) - new Double(setting.getAmStartTime()) + new Double(setting.getPmEndTime()) - new Double(setting.getPmStartTime())).intValue()*setting.getNumber()*60/setting.getServiceTime();
    	}
    	return 0;
    }
    
    public int getAppointmentLimitHour(Clinic clinic, String department){
    	ClinicSetting entity = new ClinicSetting();
    	entity.setClinic(clinic);
    	entity.setDepartment(department);
    	entity.setStatus("0");
    	List<ClinicSetting> settingList = clinicSettingService.findList(entity);
    	if(settingList.size()>0){
    		ClinicSetting setting = settingList.get(0);
    		return setting.getNumber()*60/setting.getServiceTime();
    	}
    	return 0;
    }
    
    public int getAppointmentCountDate(String clinicId, String department, String id, String date){
    	
    	return dao.getCount(clinicId, department, date, id, null);
    }
    
    public int getAppointmentCountTime(String clinicId, String department, String date, String id, String timePeriod){
    	
    	return dao.getCount(clinicId, department, date, id, timePeriod);
    }
	
	/**
	 * 保存数据（插入或更新）
	 * @param appointment
	 */
	@Override
	@Transactional(readOnly=false)
	public void save(Appointment appointment) {
		if("3".equals(appointment.getAppointmentStatus())){
			appointment.setTime(new Date());
		}else if("4".equals(appointment.getAppointmentStatus())){
			appointment.setFinishTime(new Date());
		}
		setAppointmentNo(appointment);
		super.save(appointment);
		ActionRecord recored = new ActionRecord();
		recored.setStatus("0");
		recored.setAppointment(appointment);
		String action = "";
		String content = "";
		Clinic clinic = null;
		if(appointment.getClinic() != null && appointment.getClinic().getId() != null){
        	clinic = clinicService.get(appointment.getClinic().getId());
        }else{
        	clinic = new Clinic();
        }
		if("1".equals(appointment.getAppointmentStatus())){
			action = "提交预约";
			content = "预约信息为，诊所:"+clinic.getName()+",科室："+DictUtils.getDictLabel("fl_department",appointment.getDepartment(),"未知")+"，时间："+ DateUtils.formatDate( appointment.getScheduledTime(), "yyyy-MM-dd ") + appointment.getTimePeriod();
		}else if("2".equals(appointment.getAppointmentStatus())){
			action = "修改预约";
			content = "修改为，诊所:"+clinic.getName()+",科室："+DictUtils.getDictLabel("fl_department",appointment.getDepartment(),"未知")+"，时间："+ DateUtils.formatDate( appointment.getScheduledTime(), "yyyy-MM-dd ") + appointment.getTimePeriod();
			recored.setReason(appointment.getReason());
			recored.setRemarks(appointment.getRemarks());
			sendSms(SmsUtils.getTemplate("apptChange"), appointment,clinic,false);
			//sendWx(WxServiceUtils.getTemplate("apptChange"), appointment,clinic,2);
		}else if("3".equals(appointment.getAppointmentStatus())){
			action = "确认预约";
			Doctor doctor = doctorService.get(appointment.getDoctor());
			content = "医师为" + doctor.getName() + ",时间为" + DateUtils.formatDate( appointment.getScheduledTime(), "yyyy-MM-dd ") + appointment.getTimePeriod();
			sendSms(SmsUtils.getTemplate("apptConfirm"), appointment,clinic,false);
			sendWx(weixinProperties.getTemplates().get("apptConfirm"), appointment,clinic,1);
		}else if("4".equals(appointment.getAppointmentStatus())){
			action = "完成预约";
			content = "";
		}else if("5".equals(appointment.getAppointmentStatus())){
			action = "取消预约";
			content = "";
			recored.setReason(appointment.getReason());
			recored.setRemarks(appointment.getRemarks());
			sendSms(SmsUtils.getTemplate("apptCancel"), appointment,clinic,true);
			sendWx(weixinProperties.getTemplates().get("apptCancel"), appointment,clinic,3);
		}
		recored.setAction(action);
		recored.setContent(content);		
		recordService.save(recored);
	}

	/**
	 * 发送短信
	 * @param appointment
	 * @param clinic
	 */
	private void sendSms(Integer templateId, Appointment appointment,Clinic clinic, boolean isCancel){
		//1是日期，2是时间片，3是诊所，4是科室，5是诊所地址，6时诊所电话
		String[] contents = new String[]{
				DateUtils.formatDate( appointment.getScheduledTime(), "yyyy-MM-dd "),
				appointment.getTimePeriod(),
				clinic.getName(),
				DictUtils.getDictLabel("fl_department",appointment.getDepartment(),"未知")+" "
		};
		if(!isCancel){
			contents = com.jeesite.common.utils.StringUtils.insert(contents,clinic.getAddress());
			contents = com.jeesite.common.utils.StringUtils.insert(contents,clinic.getTelephone());
		}
		if(appointment.getLeaguer()==null || StringUtils.isBlank(appointment.getLeaguer().getId())){
			logger.error("无法获取预约人，appointmentId:" + appointment.getId());
			return;
		}
		Leaguer leaguer = leaguerService.get(appointment.getLeaguer().getId());
		if(StringUtils.isNotBlank(leaguer.getCellphone()))
			SmsUtils.send(leaguer.getCellphone(),templateId, contents);
	}
	
	/**
	 * 发送微信
	 * @param appointment
	 * @param clinic
	 */
	private void sendWx(String templateId, Appointment appointment,Clinic clinic, int type){
		//1是日期，2是时间片，3是诊所，4是科室，5是诊所地址，6时诊所电话
		List<WxMpTemplateData> data = new ArrayList<>();
		data.add(new WxMpTemplateData("keyword2", clinic.getName(), WX_TEXT_COLOR));
		data.add(new WxMpTemplateData("keyword3", DictUtils.getDictLabel("fl_department",appointment.getDepartment(),"未知"), WX_TEXT_COLOR));
		data.add(new WxMpTemplateData("keyword1",DateUtils.formatDate( appointment.getScheduledTime(), "yyyy年MM月dd日 ")+" " + appointment.getTimePeriod().substring(0, appointment.getTimePeriod().indexOf("-")) , WX_TEXT_COLOR));
		
		if(type == 1){
			data.add(new WxMpTemplateData("first","【富乐医疗】尊敬的客户，您已成功预约：", WX_TEXT_COLOR));
			data.add(new WxMpTemplateData("keyword5",clinic.getTelephone(), WX_TEXT_COLOR));
			data.add(new WxMpTemplateData("keyword4", clinic.getAddress(), WX_TEXT_COLOR));
			data.add(new WxMpTemplateData("remark","请带好身份证件和商业保险卡（若有）。如需咨询或更改本预约，请致电诊所电话。富乐医疗，关怀您的健康。", WX_TEXT_COLOR));
		}else if(type == 2){
			data.add(new WxMpTemplateData("first","【富乐医疗】尊敬的客户，您已变更预约：", WX_TEXT_COLOR));
			data.add(new WxMpTemplateData("keyword5",clinic.getTelephone(), WX_TEXT_COLOR));
			data.add(new WxMpTemplateData("keyword4", clinic.getAddress(), WX_TEXT_COLOR));
			data.add(new WxMpTemplateData("remark","请带好身份证件和商业保险卡（若有）。如需咨询或更改本预约，请致电诊所电话。富乐医疗，关怀您的健康。", WX_TEXT_COLOR));
		}else{
			data.add(new WxMpTemplateData("first","尊敬的客户，您的预约已取消：", WX_TEXT_COLOR));
			data.add(new WxMpTemplateData("remark","富乐医疗，关怀您的健康。", WX_TEXT_COLOR));
		}
		if(appointment.getLeaguer()==null || StringUtils.isBlank(appointment.getLeaguer().getId())){
			logger.error("无法获取预约人，appointmentId:" + appointment.getId());
			return;
		}
		Leaguer leaguer = leaguerService.get(appointment.getLeaguer().getId());
		User entity = new User();
		entity.setLoginCode(leaguer.getCellphone());
		User user = userService.getByLoginCode(entity);
		if(StringUtils.isNotBlank(user.getWxOpenid()) &&
				Boolean.TRUE.equals(weixinProperties.getEnable())) {
			WxMpTemplateMessage message = WxMpTemplateMessage.builder()
					.toUser(user.getWxOpenid())
					.templateId(templateId)
					.url("")
					.data(data)
					.build();
			try {
				wxMpService.getTemplateMsgService().sendTemplateMsg(message);
			} catch (WxErrorException e) {
//				e.printStackTrace();
				logger.error("Failed to send weixin message: {}", e.getMessage());
			}
//			new WxServiceUtils().sendMessage(user.getWxOpenid(), templateId, data);
		}
	}

	/**
	 * 更新状态
	 * @param appointment
	 */
	@Override
	@Transactional(readOnly=false)
	public void updateStatus(Appointment appointment) {
		super.updateStatus(appointment);
	}
	
	/**
	 * 删除数据
	 * @param appointment
	 */
	@Override
	@Transactional(readOnly=false)
	public void delete(Appointment appointment) {
		super.delete(appointment);
		ActionRecord recored = new ActionRecord();
		recored.setStatus("0");
		recored.setAppointment(appointment);
		recored.setAction("取消预约");
		recored.setContent("");
		recored.setReason(appointment.getReason());
		recored.setRemarks(appointment.getRemarks());
		recordService.save(recored);
	}
	
	@SuppressWarnings("rawtypes")
	@Transactional(readOnly=false)
	public String importData(MultipartFile file, Boolean isUpdateSupport)
    {
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        if(file == null)
            throw new ServiceException("请选择导入的数据文件！");
        ExcelImport ei = null;
        
        try
        {
        	ei = new ExcelImport(file, 2, Integer.valueOf(0));
        	List list = ei.getDataList(Appointment.class, new String[0]);
            for(Iterator iterator = list.iterator(); iterator.hasNext();)
            {
            	Appointment appointment = (Appointment)iterator.next();
                try
                {
                	Appointment c = getByNo(appointment.getNo());
                    if(c == null)
                    {
                        save(appointment);
                        successNum++;
                        successMsg.append((new StringBuilder()).append("<br/>").append(successNum).append("、诊所 ").append(appointment.getNo()).append(" 导入成功").toString());
                    } else if(isUpdateSupport.booleanValue())
                    {
                    	appointment.setId(c.getId());
                        save(appointment);
                        successNum++;
                        successMsg.append((new StringBuilder()).append("<br/>").append(successNum).append("、预约 ").append(appointment.getNo()).append(" 更新成功").toString());
                    } else
                    {
                        failureNum++;
                        failureMsg.append((new StringBuilder()).append("<br/>").append(failureNum).append("、预约 ").append(appointment.getNo()).append(" 已存在").toString());
                    }
                }
                catch(Exception e)
                {
                    failureNum++;
                    String msg = (new StringBuilder()).append("<br/>").append(failureNum).append("、预约 ").append(appointment.getNo()).append(" 导入失败：").toString();
                    if(e instanceof ConstraintViolationException)
                    {
                        List messageList = ValidatorUtils.extractPropertyAndMessageAsList((ConstraintViolationException)e, ": ");
                        for(Iterator iterator1 = messageList.iterator(); iterator1.hasNext();)
                        {
                            String message = (String)iterator1.next();
                            msg = (new StringBuilder()).append(msg).append(message).append("; ").toString();
                        }

                    } else
                    {
                        msg = (new StringBuilder()).append(msg).append(e.getMessage()).toString();
                    }
                    failureMsg.append(msg);
                    logger.error(msg, e);
                }
            }

        }
        catch(Throwable throwable2)
        {
        	throwable2.printStackTrace();
        }
        finally
        {
            if(ei != null) 
            	ei.close();
        }
        if(failureNum > 0)
        {
            failureMsg.insert(0, (new StringBuilder()).append("很抱歉，导入失败！共 ").append(failureNum).append(" 条数据格式不正确，错误如下：").toString());
            throw new ServiceException(failureMsg.toString());
        } else
        {
            successMsg.insert(0, (new StringBuilder()).append("恭喜您，数据已全部导入成功！共 ").append(successNum).append(" 条，数据如下：").toString());
            return successMsg.toString();
        }
    }

    /*
    * 得到差评数
    * */
	public Integer getLowLevelEvaluateCount(){
		return dao.getLowLevelEvaluateCount();
	};

	@Transactional(readOnly=false)
	public void saveEvaluate(String appointmentId, List<Evaluate> evaluateScoreList, EvaluateDetail evaluateDetail){
		Appointment appointment = new Appointment(appointmentId);
		if(evaluateScoreList!=null && evaluateScoreList.size()>0) {
			for (Evaluate evaluate : evaluateScoreList) {
				if(StringUtils.isBlank(evaluate.getType())) continue;;
				evaluate.setAppointment(appointment);
				Evaluate evaluateFilter = new Evaluate(appointment);
				evaluateFilter.setAppointment(appointment);
				evaluateFilter.setType(evaluate.getType());
				evaluateFilter.setStatus(Evaluate.STATUS_NORMAL);
				List<Evaluate> savedEvaluates = evaluateDao.findList(evaluateFilter);
				if (savedEvaluates != null && savedEvaluates.size()>0) {
					Evaluate savedEvaluate = savedEvaluates.get(0);
					savedEvaluate.setScore(evaluate.getScore());
					evaluate.preUpdate();
					evaluateDao.update(savedEvaluate);
				} else {
					evaluate.preInsert();
					evaluateDao.insert(evaluate);
				}
			}
		}
		if(evaluateDetail!=null) {
			evaluateDetail.preInsert();
			evaluateDetail.setAppointment(appointment);
			evaluateDetail.setSource("1");
			evaluateDetailDao.insert(evaluateDetail);
		}

		appointment.preUpdate();
		appointment.setIsEvaluate("1");
		dao.update(appointment);
	}

	/**
	 * 得到预约人没有看的评价数
	 * @param leaguerId
	 * @return
	 */
	public Integer getUnReadEvalCount(String leaguerId){
		return dao.getUnReadEvalCount(leaguerId);
	}

	//处理差评
	@Transactional(readOnly=false)
	public void endPoorRating(Appointment appointment){
		dao.endPoorRating(appointment);
	}
}
